﻿using FriendAnalyzer.Business.Model;
using FriendAnalyzer.Infrastructure.Facebook.Interfaces;
using FriendAnalyzer.Infrastructure.Facebook.Model;
using FriendAnalyzer.Infrastructure.Files;
using FriendAnalyzer.Infrastructure.MachineLearning.Analysis;
using FriendAnalyzer.Infrastructure.MachineLearning.Model;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System;
using FriendAnalyzer.Business.FacebookFilter;
namespace FriendAnalyzer.Business
{
    public class AggregateService
    {
        private IFriendsAPI _api;
        private IFileManager _fileManager;
        private List<FacebookUser> usersData;
        private List<BaseAggregationStrategy> facebookFilters = new List<BaseAggregationStrategy>();

        public AggregateService(IFriendsAPI api, IFileManager fileManager)
        {
            _api = api;
            _fileManager = fileManager;
        }

        public async Task<List<FacebookUser>> GetFriendsDataAsync(bool refresh = false)
        {
            if (usersData == null)
            {
                usersData = await _api.AggregateFriendsDataAsync();
            }

            var images = await _fileManager.GetImagesAsync();
            if (images.Count != usersData.Count)
            {
                await _fileManager.DownloadFilesAsync(usersData);
            }

            return usersData;
        }

        private Dictionary<ulong, double[]> GetAggregatedFeatures(IEnumerable<AggregateResult> data)
        {
            int i = 0;
            var indicesByUserId = usersData.Select(u => u.UserID).OrderBy(u => u).ToDictionary(u => u, u => i++);

            var aggregatedFeatures = new Dictionary<ulong, double[]>();
            foreach (var userId in indicesByUserId.Keys)
            {
                aggregatedFeatures[userId] = new double[indicesByUserId.Keys.Count];
            }

            foreach (var relation in data)
            {
                aggregatedFeatures[relation.User1][indicesByUserId[relation.User2]] = aggregatedFeatures[relation.User2][indicesByUserId[relation.User1]] 
                    =  /*relation.User1 == relation.User2 ? 0 :*/ relation.ItemsInCommon;
            }
             
            return aggregatedFeatures;
        }

        public void AddFacebookFilter(BaseAggregationStrategy facebookFilter)
        {
            facebookFilters.Add(facebookFilter);
        }

        public async Task<Dictionary<FacebookUser, FacebookUser[]>> GetGroupedFacebookUsers(uint leaderCount, double accuracy, double fuzzyness, double maxStepCount)
        {
                usersData = await GetFriendsDataAsync();
            usersData = usersData.OrderBy(cc => Guid.NewGuid()).Take(100).ToList();

            var featureBuilder = new FacebookUserFeatureBuilder();

            foreach (var filter in facebookFilters)
            {
                featureBuilder.AddFeatures(GetAggregatedFeatures(filter.AggregateData(usersData)));
            }

            var classifier = FacebookDataAnalyzer.Instance.GetUserClassifier(featureBuilder.GetUserFeatureData(), leaderCount, accuracy, fuzzyness, maxStepCount, false);
            classifier.Compute(true);

            var result = classifier.GetGroupedUsers().ToDictionary(u => usersData.First(ud => ud.UserID == u.Key.UserId), u => u.Value.Select(x => usersData.First(y => y.UserID == x.UserId)).ToArray());
            return result;

            //var usersById = usersData.ToDictionary(u => u.UserID);
            //var classifiedUserNames = classifiedUsers.Select(u => u.Value.Aggregate(new StringBuilder(), (s, v) => s.Append(", " + usersById[v.UserId].FirstName + " " + usersById[v.UserId].LastName)).ToString());
        }
    }
}